﻿using System;
using System.Collections.Generic;
using System.Drawing;
using NeuronDotNet;

namespace AdvancedTSPSolver
{
  /// <summary>
  /// Class for generating rivers and bridges.
  /// Authors: Savenko Maria, Skorodumov Kirill.
  /// </summary>
  public class LandscapeGenerator
  {
    #region private fields
    private Random randomizer;
    private int defaultMapSize = 100;
    //minimum offset for river from map border
    private int minimumOffset = 15;
    #endregion

    #region public methods
    /// <summary>
    /// Creates new instance of Landscape Generator.
    /// </summary>
    /// <param name="randomizer">Generator for random numbers - usually
    /// send from the program there library is used.</param>
    public LandscapeGenerator(Random randomizer)
    {
      this.randomizer = randomizer;
    }

    /// <summary>
    /// Creates instance of River class and fills it with points.
    /// </summary>
    /// <param name="numberOfBridges">Number of bridges on the river. Note that 
    /// it will generate no less that 1 bridge and no more than number
    /// of points in the river.</param>
    /// <returns>Fully usable instance of River class.</returns>
    public DrawableRiver GenerateRiverWithBridges(int numberOfBridges = 2)
    {
      DrawableRiver river = new DrawableRiver();
      river.RiverDirection = (River.RiverDirections)randomizer.Next(2);
      river.OffsetFromBorder = 
        randomizer.Next(minimumOffset, defaultMapSize - minimumOffset);
      GenerateRiverPoints(river);

      numberOfBridges = 
        Math.Max(1, Math.Min(numberOfBridges, river.RiverBank.Count));
      river.Bridges = GenerateBridgesPoints(numberOfBridges, river.RiverBank);

      return river;
    }
    #endregion

    #region private methods
    /// <summary>
    /// Generates river points only.
    /// </summary>
    /// <param name="river">River class instance to fill with points and
    /// to take info about it's curve equation.</param>
    private void GenerateRiverPoints(River river)
    {
      List<PointF> riverPoints = new List<PointF>();

      for (int i = 1; i < defaultMapSize + 10; i += 5)
      {
        float value = river.RiverCurve(i);
        if (river.RiverDirection == River.RiverDirections.FromLeftToRight)
        {
          riverPoints.Add(new PointF((float)i, value));
        }
        else
        {
          riverPoints.Add(new PointF(value, (float)i));
        }
      }

      river.RiverBank = riverPoints;
    }

    /// <summary>
    /// Generates even number of bridges on the river.
    /// </summary>
    /// <param name="numberOfBridges">Number of bridges to generate.</param>
    /// <param name="riverBank">River points.</param>
    private List<PointF> GenerateBridgesPoints(
      int numberOfBridges, List<PointF> riverBank)
    {
      List<PointF> bridges = new List<PointF>();
      int riverPointsCount = riverBank.Count;

      while (bridges.Count < numberOfBridges)
      {
        int randomPoint = randomizer.Next(0, riverPointsCount - 1);
        PointF bridge = riverBank[randomPoint];
        if (bridges.Contains(bridge))
        {
          continue;
        }
        bridges.Add(bridge);
      }

      return bridges;
    }
    #endregion
  }
}
